﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp5
{
    partial class PeParse
    {
        public PEReader reader;
        /// <summary>
        /// 需要一个 PEReader 作为读取器
        /// </summary>
        /// <param name="reader">PEReader 读取器</param>
        public PeParse(PEReader reader)=>
            this.reader = reader;

        /// <summary>
        /// 通过 RVA 获得对应位置的二进制读取器
        /// </summary>
        /// <param name="Rva">镜像Rva</param>
        /// <returns>二进制读取器</returns>
        public BlobReader GetRvaBlob(Int64 Rva)
        {
            PEMemoryBlock memoryBlock = reader.GetSectionData((int)Rva);
            return memoryBlock.GetReader();
        }

        /// <summary>
        /// 通过二进制读取器读取以0结尾的Ansi字符
        /// </summary>
        /// <param name="blobReader">二进制读取器</param>
        /// <returns>Ansi字符串</returns>
        public string ParseCharVector(BlobReader blobReader)
        {
            List<byte> result = new();
            byte charData;
            do {
                charData = blobReader.ReadByte();
                result.Add(charData);
            } while (charData != 0);
            return Encoding.ASCII.GetString(result.ToArray());
        }

        /// <summary>
        /// 通过Rva读取器读取以0结尾的Ansi字符
        /// </summary>
        /// <param name="Rva">镜像Rva</param>
        /// <returns>Ansi字符串</returns>
        public string ParseCharVector(Int32 Rva)
        {
            return ParseCharVector(GetRvaBlob(Rva));
        }
        /// <summary>
        /// 通过二进制读取器解析 IMAGE_IMPORT_BY_NAME 结构
        /// </summary>
        /// <param name="blobReader">二进制读取器</param>
        /// <returns>IMAGE_IMPORT_BY_NAME 结构</returns>
        public ImportByName ParseImportByName(BlobReader blobReader)
        {
            ImportByName result;
            result.Hint = blobReader.ReadUInt16();
            result.Name = ParseCharVector(blobReader);
            return result;
        }
        /// <summary>
        /// 通过二进制读取器解析连续的 IMAGE_THUNK_DATA 结构
        /// </summary>
        /// <param name="blobReader">二进制读取器</param>
        /// <returns>IMAGE_THUNK_DATA 数组</returns>
        public List<ThunkData> ParseThunkData(BlobReader blobReader)
        {
            List<ThunkData> thunkList = new();
            ThunkData thunkData = new ThunkData();
            while (true)
            {
                if (reader.PEHeaders.PEHeader.Magic == PEMagic.PE32Plus)
                {
                    Int64 to32 = blobReader.ReadInt64();
                    // 可能存在溢出，由于C# 的GetSectionData只能支持 Int32 所以无法解决。
                    to32 = (int)(to32 & int.MaxValue) | (to32 < 0 ? int.MinValue : 0);
                    thunkData.ForwarderString = (int)to32;

                }
                else
                    thunkData.ForwarderString = blobReader.ReadInt32();

                if (thunkData.ForwarderString == 0)
                    break;

                thunkList.Add(thunkData);
            }
            return thunkList;
        }
        /// <summary>
        /// 解析PE文件格式中的导入描述符表数组 - IMAGE_IMPORT_DESCRIPTOR
        /// </summary>
        /// <returns>IMAGE_IMPORT_DESCRIPTOR 数组</returns>
        public List<ImportDescriptor> ParseImportDescriptor()
        {
            // 获取导入表RVA 和 Size
            PEHeader peHeader = reader.PEHeaders.PEHeader;
            Int32 importRva = peHeader.ImportTableDirectory.RelativeVirtualAddress;
            Int32 importSize = peHeader.ImportTableDirectory.Size;

            // 获得导入表数据
            BlobReader importMemoryReader = GetRvaBlob(importRva);
            byte[] importMemory = importMemoryReader.ReadBytes(importSize);

            // 为每个ImportDescriptor分配内存，并拷贝bytes数据
            List<ImportDescriptor> descriptors = new();
            int size = Marshal.SizeOf<ImportDescriptor>();
            IntPtr memoryImport = Marshal.AllocHGlobal(importMemory.Length);
            for (int i = 0; i < importMemory.Length / size; i++)
            {
                Marshal.Copy(importMemory, i * size, memoryImport, size);
                ImportDescriptor descriptor = Marshal.PtrToStructure<ImportDescriptor>(memoryImport);
                if (descriptor.Characteristics == 0)
                    break;

                descriptors.Add(descriptor);
            }
            Marshal.FreeHGlobal(memoryImport);
            return descriptors;
        }
    }
}
